#include <glib.h>
#include "GEventWrapper.h"
#include "GThreadWrapper.h"

gulong CGThreadWrapper::s_threadsRunnig = 0;
gulong CGThreadWrapper::s_threadsCreated = 0;

CGThreadWrapper::CGThreadWrapper(const gchar *name)
:m_thread(NULL)
,m_running(FALSE)
{
  m_name = g_strdup(name);
  m_event.Create(FALSE /*manualReset*/, FALSE /*initialState*/);
}

CGThreadWrapper::~CGThreadWrapper()
{
  DestroyThread();
  g_free(m_name);
}

gboolean CGThreadWrapper::CreateThread(gboolean sync /*=TRUE*/)
{
  if(!g_thread_supported())
    return FALSE;

  /* already created */
  if(m_thread)
    return FALSE;

  GError *error = NULL;
#if GLIB_CHECK_VERSION(2, 32, 0)
  m_thread = g_thread_try_new(m_name, CGThreadWrapper::ThreadProc, this, &error);
#else
  m_thread = g_thread_create(CGThreadWrapper::ThreadProc, this, TRUE, &error);
#endif
  if(!m_thread)
  {
    /*(error->code==G_THREAD_ERROR_AGAIN)... ALWAYS FAIL*/
    g_print("Error starting thread \"%s\" (%s) (%lu, %lu)\n", m_name, error? error->message : NULL, s_threadsCreated, s_threadsRunnig);
    g_error_free(error);
    return FALSE;
  }
  g_print("Thread \"%s\" created (created: %lu, running: %lu)\n", m_name, s_threadsCreated, s_threadsRunnig);

  /* sync creation */
  if(sync)
    m_event.Wait();

  return TRUE;
}

gboolean CGThreadWrapper::DestroyThread()
{
  /* if the thrad ends before DestroyThread is called, the m_thread
   * needs to be join in order to decrement the reference */
  m_running = FALSE;

  if(m_thread)
  {
    g_thread_join(m_thread);
    g_print("Thread \"%s\" destroyed (created: %lu, running: %lu)\n", m_name, s_threadsCreated, s_threadsRunnig);
  }
  m_thread = NULL;

  return TRUE;
}

gpointer CGThreadWrapper::ThreadProc(gpointer params)
{
  CGThreadWrapper *thread = reinterpret_cast<CGThreadWrapper *> (params);
  thread->m_running = TRUE;
  thread->m_event.Set();

  CGThreadWrapper::s_threadsRunnig++;
  CGThreadWrapper::s_threadsCreated++;

  thread->RunThread();

  CGThreadWrapper::s_threadsRunnig--;
  thread->m_running = FALSE;

  g_print("Thread \"%s\" ends runnig (created: %lu, running: %lu) \n", thread->m_name, CGThreadWrapper::s_threadsCreated, CGThreadWrapper::s_threadsRunnig);

  return NULL;
}

gulong CGThreadWrapper::RunThread()
{
  gboolean runLoop = TRUE;
  while(m_running && runLoop)
  {
    runLoop = RunLoop();
    g_thread_yield();
  }

  return 0x007;
}
